﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Library.Common.Reflection
{
    /// <summary>
    /// 反射帮助类
    /// </summary>
    public class ReflectionHelper
    {
        /// <summary>
        /// 反射加载程序集获取所有Type[]
        /// </summary>
        /// <param name="fullName"></param>
        /// <param name="asm"></param>
        /// <returns></returns>
        public static Type[] GetType(string fullName, ref Assembly asm)
        {
            Type[] types = null;
            string exeName = AppDomain.CurrentDomain.FriendlyName;
            string assemblyName = fullName.Substring(0, fullName.IndexOf("."));
            asm = Assembly.Load(assemblyName);
            types = asm.GetTypes();
            return types;
        }

        /// <summary>
        /// 反射加载程序集获取所有Type
        /// </summary>
        /// <param name="assemblyName">类型所在程序集名称</param>
        /// <param name="fullName">命名空间.类型名</param>
        /// <returns></returns>
        public static Type GetType(string assemblyName, string fullName)
        {
            Type result = null;
            try
            {
                Assembly assembly = Assembly.Load(assemblyName);
                Type[] types = assembly.GetTypes();
                foreach (var t in types)
                {
                    //返回结果:表示具有指定名称且由当前的 System.Type 实现或继承的接口的对象（如果找到的话）；否则为 null。
                    if (t.FullName == fullName)
                    {
                        result = t;
                    }
                }
            }
            catch
            {
                //发生异常，返回类型的默认值
                return null;
            }
            return result;
        }

        /// <summary>
        /// 获取PropertyName
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static string GetPropertyName<T>(Expression<Func<T, object>> exp)
        {
            MemberExpression body = null;
            if (exp.Body is MemberExpression)
            {
                body = exp.Body as MemberExpression;
            }
            else if (exp.Body is UnaryExpression)
            {
                UnaryExpression expression2 = exp.Body as UnaryExpression;
                if (expression2.Operand is MemberExpression)
                {
                    body = expression2.Operand as MemberExpression;
                }
            }
            if (body == null)
            {
                throw new InvalidOperationException("Not a member access.");
            }
            PropertyInfo member = body.Member as PropertyInfo;
            return member.Name;
        }


        /// <summary>
        /// 创建对象实例
        /// </summary>
        /// <typeparam name="T">要创建对象的类型</typeparam>
        /// <param name="assemblyName">类型所在程序集名称</param>
        /// <param name="nameSpace">类型所在命名空间</param>
        /// <param name="className">类型名</param>
        /// <returns></returns>
        public static T CreateInstance<T>(string assemblyName, string nameSpace, string className)
        {
            try
            {
                string fullName = nameSpace + "." + className;//命名空间.类型名
                //此为第一种写法
                object ect = Assembly.Load(assemblyName).CreateInstance(fullName);//加载程序集，创建程序集里面的 命名空间.类型名 实例
                return (T)ect;//类型转换并返回
                //下面是第二种写法
                //string path = fullName + "," + assemblyName;//命名空间.类型名,程序集
                //Type o = Type.GetType(path);//加载类型
                //object obj = Activator.CreateInstance(o, true);//根据类型创建实例
                //return (T)obj;//类型转换并返回
            }
            catch
            {
                //发生异常，返回类型的默认值
                return default(T);
            }
        }

        /// <summary>
        /// 创建对象实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fullName">命名空间.类型名</param>
        /// <param name="assemblyName">程序集</param>
        /// <returns></returns>
        public static T CreateInstance<T>(string fullName, string assemblyName)
        {
            string path = fullName + "," + assemblyName;//命名空间.类型名,程序集
            Type o = Type.GetType(path);//加载类型
            object obj = Activator.CreateInstance(o, true);//根据类型创建实例
            return (T)obj;//类型转换并返回
        }
    }
}
